﻿/* EntitiesToDTOs. Copyright (c) 2012. Fabian Fernandez.
 * http://entitiestodtos.codeplex.com
 * Licensed by Common Development and Distribution License (CDDL).
 * http://entitiestodtos.codeplex.com/license
 * Fabian Fernandez. 
 * http://www.linkedin.com/in/fabianfernandezb/en
 * */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;
using EntitiesToDTOs.Domain;
using EntitiesToDTOs.Properties;

namespace EntitiesToDTOs.Helpers
{
    /// <summary>
    /// Provides advertising operations.
    /// </summary>
    internal class AdvertHelper
    {
        /// <summary>
        /// Specifies adverts config file nodes used.
        /// </summary>
        private class AdvertsConfigNodes
        {
            public static string Advert = "Advert";
            public static string AdvertAttrId = "id";
            public static string AdvertAttrCompiled = "compiled";
            public static string AdvertAttrEnabled = "enabled";

            public static string Link = "Link";
            public static string LinkAttrUrl = "url";

        }



        /// <summary>
        /// Indicates if advert logic is initialized.
        /// </summary>
        private static bool IsInitialized { get; set; }

        /// <summary>
        /// Folder where advert images are stored once downloaded.
        /// </summary>
        private static string AdvertsLocalFolder
        {
            get
            {
                return (Path.GetTempPath() + Resources.EntitiesToDTOsTempFolderName + Resources.AdvertsFolderName);
            }
        }

        /// <summary>
        /// Advert-xml config file path.
        /// </summary>
        private static string AdvertsConfigFilePath
        {
            get
            {
                return (AdvertHelper.AdvertsLocalFolder + Resources.AdvertsConfigFileName);
            }
        }

        /// <summary>
        /// Default advert.
        /// </summary>
        private static Advert DefaultAdvert
        {
            get
            {
                if (AdvertHelper.defaultAdvert == null)
                {
                    AdvertHelper.defaultAdvert = new Advert();
                    AdvertHelper.defaultAdvert.Image = Resources.AdTemplate;
                    AdvertHelper.defaultAdvert.LinkURL = Resources.AdvertDefaultLinkURL;
                }

                return AdvertHelper.defaultAdvert;
            }
        }
        private static Advert defaultAdvert = null;

        /// <summary>
        /// Adverts that are compiled with the tool.
        /// </summary>
        private static List<Advert> CompiledAdverts
        {
            get
            {
                if (AdvertHelper.compiledAdverts == null)
                {
                    AdvertHelper.compiledAdverts = new List<Advert>();

                    // LinkURL could be updated by advert-xml obtained from repository

                    // TODO: ffernandez, include real compiled adverts here

                    //AdvertHelper.compiledAdverts.Add(new Advert() 
                    //{ 
                    //    AdvertID = 1, 
                    //    Image = Resources.Advert_1,
                    //    LinkURL = "http://entitiestodtos.codeplex.com"
                    //});
                }

                return AdvertHelper.compiledAdverts;
            }
        }
        private static List<Advert> compiledAdverts = null;

        /// <summary>
        /// Available adverts.
        /// </summary>
        public static List<Advert> AvailablesAdverts { get; set; }



        /// <summary>
        /// Initializes advert logic.
        /// </summary>
        public static void Init()
        {
            if (AdvertHelper.IsInitialized == false)
            {
                AdvertHelper.IsInitialized = true;
                AdvertHelper.AvailablesAdverts = new List<Advert>();

                try
                {
                    // Create advert local folder if not exists
                    if (Directory.Exists(AdvertHelper.AdvertsLocalFolder) == false)
                    {
                        Directory.CreateDirectory(AdvertHelper.AdvertsLocalFolder);
                    }

                    // Get advert-xml from repository
                    XDocument xdoc = XDocument.Load(Resources.AdvertsBaseURL + Resources.AdvertsConfigFileName);

                    // Update latest advert-xml downloaded with the new one
                    xdoc.Save(AdvertHelper.AdvertsConfigFilePath);
                }
                catch (Exception ex)
                {
                    AdvertHelper.IsInitialized = false;

                    // Log error
                    LogManager.LogError(ex);
                }

                try
                {
                    if (File.Exists(AdvertHelper.AdvertsConfigFilePath) == false)
                    {
                        // Adverts config file is missing
                        throw new ApplicationException(Resources.Error_AdvertsConfigMissing);
                    }
                    else
                    {
                        // Load adverts config file
                        XDocument xdoc = XDocument.Load(AdvertHelper.AdvertsConfigFilePath);

                        // Get enabled adverts
                        IEnumerable<XElement> advertsFromConfig = xdoc.Descendants(AdvertsConfigNodes.Advert)
                            .Where(n => n.Attribute(AdvertsConfigNodes.AdvertAttrEnabled)
                                .Value.ToLower() == (true).ToString().ToLower());

                        // Loop through adverts from config
                        foreach (XElement advertNode in advertsFromConfig)
                        {
                            var advert = new Advert();

                            // Get Advert ID
                            advert.AdvertID = Convert.ToInt32(advertNode.Attribute(AdvertsConfigNodes.AdvertAttrId).Value);

                            // Get Link URL
                            advert.LinkURL = advertNode.Descendants(AdvertsConfigNodes.Link).First()
                                .Attribute(AdvertsConfigNodes.LinkAttrUrl).Value;

                            // Get compiled attribute value
                            string compiledValue = advertNode.Attribute(AdvertsConfigNodes.AdvertAttrCompiled).Value;

                            if (compiledValue.ToLower() == (true).ToString().ToLower())
                            {
                                // Advert is compiled, get image from CompiledAdverts
                                Advert advertCompiled =
                                    AdvertHelper.CompiledAdverts.FirstOrDefault(a => a.AdvertID == advert.AdvertID);

                                if (advertCompiled != null)
                                {
                                    advert.Image = advertCompiled.Image;
                                }
                                else
                                {
                                    // Advert is marked as compiled but was not found in resources, 
                                    // continue with next advert
                                    continue;
                                }
                            }
                            else
                            {
                                // Compose advert image name
                                string advertImageName =
                                    string.Format(Resources.AdvertImageFileName, advert.AdvertID.ToString());

                                // Check if image was NOT downloaded
                                if (File.Exists(AdvertHelper.AdvertsLocalFolder + advertImageName) == false)
                                {
                                    try
                                    {
                                        // Download image
                                        (new WebClient()).DownloadFile(Resources.AdvertsBaseURL + advertImageName,
                                            AdvertHelper.AdvertsLocalFolder + advertImageName);
                                    }
                                    catch (Exception ex)
                                    {
                                        // Log error
                                        LogManager.LogError(ex);

                                        // Image could not be downloaded, continue with next advert
                                        continue;
                                    }
                                }

                                // Get image from file system
                                using (FileStream imgStream = File.OpenRead(AdvertHelper.AdvertsLocalFolder + advertImageName))
                                {
                                    advert.Image = new Bitmap(imgStream);
                                }
                            }

                            // Add to available adverts
                            AdvertHelper.AvailablesAdverts.Add(advert);

                        } // END foreach (XElement advertNode in advertsFromConfig)

                    } // END else
                }
                catch (Exception ex)
                {
                    AdvertHelper.IsInitialized = false;

                    // Log error
                    LogManager.LogError(ex);

                    // Indicate all compiled adverts as available adverts
                    AdvertHelper.AvailablesAdverts = new List<Advert>();
                    foreach (Advert compiledAd in AdvertHelper.CompiledAdverts)
                    {
                        AdvertHelper.AvailablesAdverts.Add(compiledAd);
                    }
                }

                if (AdvertHelper.AvailablesAdverts.Count == 0)
                {
                    // No available adverts, show default advert
                    AdvertHelper.AvailablesAdverts.Add(AdvertHelper.DefaultAdvert);
                }

            } // END if (AdvertHelper.IsInitialized == false)
        }

        /// <summary>
        /// Shuffle available adverts.
        /// </summary>
        public static void ShuffleAdverts()
        {
            // Shuffle available adverts
            AdvertHelper.AvailablesAdverts = AdvertHelper.AvailablesAdverts.OrderBy(a => Guid.NewGuid()).ToList();
        }


    }
}